/*!
\file Enemy.h
\author Po
\brief Contains Bullet, Gun, Enemy and Barrack. Gun manage Bullet. Barrack manage Enemy.
*/
#pragma once

#include <list>
#include <d3d9.h>
#include <d3dx9.h>

/*!
\class Bullet
\brief A sphere object can move to a direction when Bullet::Update() called.
*/
class Bullet
{
public:
	/*! Construct a bullet with a IDirect3DDevice9 (<b>NOT</b> own this device), position vector and direction vector. */
	Bullet(IDirect3DDevice9 *pd3dDevice, D3DXVECTOR3 *pVecPosition, D3DXVECTOR3 *pDirection);
	/*! Destruct the bullet. */
	~Bullet();

public:
	/*! Return current position. */
	const D3DXVECTOR3 &Position();
	/*! Return bullet fly distance. */
	float Distance() const;
	/*! Return the bullet sphere radius. */
	float Radius() const;
	/*! Kill this bullet, set alive false, and this bullet will be destruct when next Gun::Update() called. */
	void Kill();
	/*! Check whether this bullet is alive. */
	bool Alive() const;

public:
	/*! Should call this function one frame a time. */
	void Update();

private:
	Bullet(const Bullet &);
	Bullet &operator=(const Bullet &);

private:
	LPDIRECT3DDEVICE9 m_pd3dDevice;
	LPD3DXMESH m_pMesh;
	D3DXMATRIX m_matPosition;
	D3DXVECTOR3 m_vecPosition;
	D3DXVECTOR3 m_vecDirection;
	float m_fRadius;
	float m_fSpeed;
	float m_fDistance;
	bool m_bAlive;
};

/*!
\class Gun
\brief Manage Bullet.
*/
class Gun
{
public:
	/*! Construct a gun with a IDirect3DDevice9 (<b>NOT</b> own this device) and shoot range. */
	Gun(IDirect3DDevice9 *pd3dDevice, float fRange);
	/*! Destruct the gun, if no gun instance exists, destruct all Gun::Bullets(). */
	~Gun();

public:
	/*! Construct a Bullet with position and direction, and add this bullet to Gun::Bullets(). */
	void Fire(D3DXVECTOR3 *vecPosition, D3DXVECTOR3 *vecDirection);

public:
	/*! Should call this function one frame a time. */
	void Update();

public:
	/*! Contains all bullets. Bullet can only be destructed by call Bullet::Kill(). */
	static std::list<Bullet *> &Bullets();

private:
	LPDIRECT3DDEVICE9 m_pd3dDevice;
	float m_fRange;

private:
	static std::list<Bullet *> sm_vecBullet;
	static int sm_nInstanceCount;
};

/*!
\class Enemy
\brief A sphere object can move from position to the destination with a certain speed.
*/
class Enemy
{
public:
	/*! Construct a gun with a IDirect3DDevice9 (<b>NOT</b> own this device), from vector, to vector, speed. */
	Enemy(IDirect3DDevice9 *pd3dDevice, D3DXVECTOR3 *pVecFrom, D3DXVECTOR3 *pVecTo, float fSpeed);
	/*! Destruct the enemy. */
	~Enemy();

public:
	/*! Return current position. */
	const D3DXVECTOR3 &Position();
	/*! Return enemy run distance. */
	float Distance() const;
	/*! Return the enemy sphere radius. */
	float Radius() const;
	/*! Kill this enemy, set alive false, and this enemy will be destruct when next Barrack::Update() called. */
	void Kill();
	/*! Check whether this enemy is alive. */
	bool Alive() const;

public:
	/*! Should call this function one frame a time. */
	void Update();

private:
	Enemy(const Enemy &);
	Enemy &operator=(const Enemy &);

private:
	LPDIRECT3DDEVICE9 m_pd3dDevice;
	LPD3DXMESH m_pMesh;
	D3DXMATRIX m_matTransform;
	D3DXVECTOR3 m_vecPosition;
	D3DXVECTOR3 m_vecFrom;
	D3DXVECTOR3 m_vecTo;
	float m_fRadius;
	float m_fSpeed;
	float m_fDistance;
	bool m_bAlive;
};

/*!
\class Barrack
\brief Manage Enemy.
*/
class Barrack
{
public:
	/*! Construct a barrack with a IDirect3DDevice9 (<b>NOT</b> own this device) and max enemy run distance. */
	Barrack(IDirect3DDevice9 *pd3dDevice, float fMaxPath);
	/*! Destruct the barrack, if no barrack instance exists, destruct all Barrack::Enemies(). */
	~Barrack();

public:
	/*! Construct a Enemy with from and to, and add this enemy to Barrack::Enemies(). */
	void Attack(D3DXVECTOR3 *vecFrom, D3DXVECTOR3 *vecTo);

public:
	/*! Should call this function one frame a time. */
	void Update();

public:
	/*! Contains all enemies. Enemy can only be destructed by call Enemy::Kill(). */
	static std::list<Enemy *> &Enemies();

private:
	LPDIRECT3DDEVICE9 m_pd3dDevice;
	float m_fMaxPath;

private:
	static std::list<Enemy *> sm_vecEnemy;
	static int sm_nInstanceCount;
};

